import { DB } from "../db"
import { ServerValues } from "../../../kds-base-define/src/ServerConfig"
import { Rpc } from "../rpc"
import { kdRpcMsg } from "kdweb-core/lib/rpc/protocols"
import { Log } from "../log"
import { RoomDefine } from "../../../kds-base-define/src/RoomDefine"
import { UserDefine } from "../../../kds-base-define/src/UserDefine"
import { kdutils } from "kdweb-core/lib/utils"
import { mongoDB } from "kdweb-core/lib/mongo/controller"
import { RoomCodeID } from "./room_id_code"

let db = DB.get(ServerValues.dbRoom,"room-normal")
let roomTableName = "t_room"
let realtimeTableName = "t_real_status"
async function createRoom(h:string,roomPOData:RoomDefine.RoomPOData) {
	await removeRoom(h,roomPOData.boxCode)
	let count = await db.insert(roomTableName,roomPOData)
	let b = count > 0
	if(b) {
		let realtimeData:RoomDefine.RoomRealtimeData = {
			boxCode:roomPOData.boxCode,
			roomID:roomPOData.roomID,
			status:RoomDefine.RoomStatusType.Virtual,
			userScores:[],
			userInfos:[],

			gsTag:null,
			gsTimestamp:null,
		}
		b = await createRoomRealtime(h,realtimeData)
		if(!b) {
			Log.oth.info("create room realtime failed ",roomPOData)
			await removeRoom(h,roomPOData.boxCode)
		}
	}
	if(b) {
		await RoomCodeID.createMap(roomPOData.boxCode,roomPOData.roomID)
	}
	return b 
} 

async function removeRoom(h:string,codeOrID:string | number) {
	let idx = {}
	if(typeof(codeOrID) == "string") {
		idx = {boxCode:codeOrID}
	} else {
		idx = {roomID:codeOrID}
	}
	let roomPOData = await getRoom(h,codeOrID)
	if(roomPOData == null) {
		return null 
	}
	let count = await db.delMany(roomTableName,idx)
	await removeRoomRealtime(h,roomPOData.boxCode)
	await RoomCodeID.delMap(roomPOData.boxCode,roomPOData.roomID)
	return roomPOData
}

async function getRoom(h:string,codeOrID:string | number) {
	let idx = {}
	if(typeof(codeOrID) == "string") {
		idx = {boxCode:codeOrID}
	} else {
		idx = {roomID:codeOrID}
	}
	let roomPOData:RoomDefine.RoomPOData = await db.getSingle(roomTableName,idx)
	return roomPOData
}

async function getRoomIDByBoss(h:string,userIDOrSK:number | string) {
	let idx = {}
	if(typeof(userIDOrSK) == "string") {
		idx = {"roomData.bossSK":userIDOrSK}
	} else {
		idx = {"roomData.bossUserID":userIDOrSK}
	}
	let roomPOData:RoomDefine.RoomPOData = await db.getSingle(roomTableName,idx)
	return roomPOData != null ? roomPOData.roomID : null
}

async function getFullRoomData(h:string,codeOrID:string | number) {
	let ret:RoomDefine.RoomFullData = {
		roomPOData:null,
		roomRealtime:null
	}
	ret.roomPOData = await getRoom(h,codeOrID)
	if(ret.roomPOData == null) {
		return null
	}
	ret.roomRealtime = await getRoomRealtime(h,codeOrID)
	if(ret.roomRealtime == null) {
		return null
	}
	return ret 
}

async function getAllFullRoomData(h:string) {
	let ret:RoomDefine.RoomFullData[] = []
	let roomPODatas:RoomDefine.RoomPOData[] = await db.get(roomTableName,{})
	if(roomPODatas == null) {
		return ret 
	}
	let roomRealtimes:RoomDefine.RoomRealtimeData[] = await db.get(realtimeTableName,{})
	if(roomRealtimes == null) {
		return ret 
	}
	for(let roomPOData of roomPODatas) {
		let roomRealtime = roomRealtimes.find(v=>v.roomID == roomPOData.roomID)
		ret.push({
			roomPOData:roomPOData,
			roomRealtime:roomRealtime,
		})
	}
	return ret 
}

async function codeToID(h:string,boxCode:string) {
	// let roomPOData = await getRoom(h,boxCode)
	// if(roomPOData) {
	// 	return roomPOData.roomID
	// }
	// return null
	return await RoomCodeID.toID(boxCode)
}

let dbRealtime = DB.get(ServerValues.dbRoom,"room-realtime")
async function getRoomRealtime(h:string,codeOrID:string | number) {
	let idx = {}
	if(typeof(codeOrID) == "string") {
		idx = {boxCode:codeOrID}
	} else {
		idx = {roomID:codeOrID}
	}
	let ret:RoomDefine.RoomRealtimeData = await dbRealtime.getSingle(realtimeTableName,idx)
	return ret
}

async function createRoomRealtime(h:string,roomRealtime:RoomDefine.RoomRealtimeData) {
	let exist = await dbRealtime.getSingle(realtimeTableName,{boxCode:roomRealtime.boxCode})
	if(exist) {
		return null
	}
	return await dbRealtime.insert(realtimeTableName,roomRealtime) > 0
}

async function removeRoomRealtime(h:string,codeOrID:string | number) {
	let idx = {}
	if(typeof(codeOrID) == "string") {
		idx = {boxCode:codeOrID}
	} else {
		idx = {roomID:codeOrID}
	}
	return await dbRealtime.delMany(realtimeTableName,idx) > 0
}

async function updateRoomRealtime(h:string,roomRealtime:RoomDefine.RoomRealtimeData) {
	let idx = {boxCode:roomRealtime.boxCode}
	return await dbRealtime.update(realtimeTableName,idx,roomRealtime) >= 0
}

async function getRoomsByServer(h:string,tag:string) {
	let ret:RoomDefine.RoomRealtimeData[] = await dbRealtime.get(realtimeTableName,{gsTag:tag})
	return ret != null ? ret : []
}

async function userReport(h:string,codeOrID:string | number,userInfo:RoomDefine.ChairUserInfo,onOff:boolean) {
	let roomRealtime = await getRoomRealtime(h,codeOrID)
	if(roomRealtime == null) {
		return false 
	}
	let idx = roomRealtime.userInfos.findIndex((v)=>v.chairNo == userInfo.chairNo)
	if(idx >= 0) {
		roomRealtime.userInfos.splice(idx,1)
	}
	idx = roomRealtime.userInfos.findIndex((v)=>v.userID == userInfo.userID)
	if(idx >= 0) {
		roomRealtime.userInfos.splice(idx,1)
	}
	if(onOff) {
		roomRealtime.userInfos.push(userInfo)
	}
	return await updateRoomRealtime(h,roomRealtime)
}

// room
export let RpcRoom = {
	get:getRoom,
	getFull:getFullRoomData,
	getAllFull:getAllFullRoomData,
	create:createRoom,
	remove:removeRoom,
	boss:getRoomIDByBoss,
	id:codeToID,
}
// room.real
export let RpcRoomRealtime = {
	get:getRoomRealtime,
	update:updateRoomRealtime,
	user:userReport,
	server:getRoomsByServer,
}


let dbTea = DB.get(ServerValues.dbRoom,"room-tea")
async function getTeaRoom(h:string,teaID:number) {
	let roomPODatas:RoomDefine.RoomPOData[] = await dbTea.get(roomTableName,{"roomData.teaExt.teaID":teaID})
	if(roomPODatas == null) {
		return []
	}
	let ret:RoomDefine.RoomFullData[] = []
	for(let roomPOData of roomPODatas) {
		let roomRealtime = await getRoomRealtime(h,roomPOData.roomID)
		ret.push({
			roomRealtime:roomRealtime,
			roomPOData:roomPOData,
		})
	}
	return ret
}

// room.tea
export let RpcRoomTea = {
	get:getTeaRoom,
}